`include "defines.v"
`timescale 1ns / 1ns
module csr_reg(

    input wire clk,
    input wire rst,

    // form ex
    input wire we_i, 
    input wire[`MemAddrBus] waddr_i,
    input wire[`RegBus] data_i,

    //from id                        
    input wire[`MemAddrBus] raddr_i,
 

    // from clint
    input wire clint_we_i,                  // clint濡?虫健閸愭瑥鐦庣?涙ê娅掗弽鍥х箶
    input wire[`MemAddrBus] clint_raddr_i,  // clint濡?虫健鐠囪鐦庣?涙ê娅掗崷鏉挎絻
    input wire[`MemAddrBus] clint_waddr_i,  // clint濡?虫健閸愭瑥鐦庣?涙ê娅掗崷鏉挎絻
    input wire[`RegBus] clint_data_i,       // clint濡?虫健閸愭瑥鐦庣?涙ê娅掗弫鐗堝祦
    
    // to id
    output reg[`RegBus] data_o,  
    // to clint
    output wire global_int_en_o,            // 閸忋劌鐪稉顓熸焽娴ｈ儻鍏橀弽鍥х箶
    output reg[`RegBus] clint_data_o,       // clint濡?虫健鐠囪鐦庣?涙ê娅掗弫鐗堝祦
    output wire[`RegBus] clint_csr_mtvec,   // mtvec
    output wire[`RegBus] clint_csr_mepc,    // mepc
    output wire[`RegBus] clint_csr_mstatus // mstatus
          

    );
    reg[`DoubleRegBus] cycle;// to record the cycle of the cpu
    reg[`RegBus] mtvec; // the entrance of interruption
    reg[`RegBus] mcause;// the reason
    reg[`RegBus] mepc; // to recode the pc
    reg[`RegBus] mie; // to contron diffrent type of interruption 
    reg[`RegBus] mstatus;// the basic information of the interrupt
    reg[`RegBus] mscratch;// to store the reg information temporily

    assign global_int_en_o = (mstatus[3] == 1'b1)? `True: `False;
    assign clint_csr_mtvec = mtvec;
    assign clint_csr_mepc = mepc;
    assign clint_csr_mstatus = mstatus;
    //cycle for the central processor unit
    always @(posedge clk)
        begin
        if (rst == `RstEnable)
            begin
                cycle <= {`ZeroWord, `ZeroWord};
            end
        else
            begin
                cycle <= cycle + 1'b1;
            end

        end


    //write the csr reg, and the excute unit has the priority
    always @ (posedge clk)
        begin
            if (rst == `RstEnable)
                begin
                    //mtvec <= `ZeroWord;
                    mcause <= `ZeroWord;
                    mepc <= `ZeroWord;
                    mie <= `ZeroWord;
                    //mstatus <= `ZeroWord;
                    mscratch <= `ZeroWord;
                    mtvec <= `ZeroWord;
                    mstatus <= `ZeroWord;
                end
            else
                begin
                    if (we_i == `WriteEnable)
                    begin
                        case(waddr_i[11:0])
                            `CSR_MTVEC: begin
                                mtvec <= data_i;
                            end
                            `CSR_MCAUSE: begin
                                mcause <= data_i;
                            end
                            `CSR_MEPC: begin
                                mepc <= data_i;
                            end
                            `CSR_MIE: begin
                                mie <= data_i;
                            end
                            `CSR_MSTATUS: begin
                                mstatus <= data_i;
                            end
                            `CSR_MSCRATCH: begin
                                mscratch <= data_i;
                            end
                            default: begin

                            end
                        endcase
                    end
                    else if (clint_we_i == `WriteEnable)
                    begin
                        case (clint_waddr_i[11:0])
                        `CSR_MTVEC: begin
                            mtvec <= clint_data_i;
                        end
                        `CSR_MCAUSE: begin
                            mcause <= clint_data_i;
                        end
                        `CSR_MEPC: begin
                            mepc <= clint_data_i;
                        end
                        `CSR_MIE: begin
                            mie <= clint_data_i;
                        end
                        `CSR_MSTATUS: begin
                            mstatus <= clint_data_i;
                        end
                        `CSR_MSCRATCH: begin
                            mscratch <= clint_data_i;
                        end
                        default: begin

                        end
                        endcase
                    end
                         
                end
        end
    // read reg
    // ex
    always @ (*) begin
        if (rst == `RstEnable) begin
            data_o = `ZeroWord;
        end else begin
            if ((waddr_i[11:0] == raddr_i[11:0]) && (we_i == `WriteEnable)) begin
                data_o = data_i;
            end else begin
                case (raddr_i[11:0])
                    `CSR_CYCLE: begin
                        data_o = cycle[31:0];
                    end
                    `CSR_CYCLEH: begin
                        data_o = cycle[63:32];
                    end
                    `CSR_MTVEC: begin
                        data_o = mtvec;
                    end
                    `CSR_MCAUSE: begin
                        data_o = mcause;
                    end
                    `CSR_MEPC: begin
                        data_o = mepc;
                    end
                    `CSR_MIE: begin
                        data_o = mie;
                    end
                    `CSR_MSTATUS: begin
                        data_o = mstatus;
                    end
                    `CSR_MSCRATCH: begin
                        data_o = mscratch;
                    end
                    default: begin
                        data_o = `ZeroWord;
                    end
                endcase
            end
        end
    end

    // read reg
    // clint
    always @ (*) begin
        if (rst == `RstEnable) begin
            clint_data_o = `ZeroWord;
        end else begin
            if ((clint_waddr_i[11:0] == clint_raddr_i[11:0]) && (clint_we_i == `WriteEnable)) begin
                clint_data_o = clint_data_i;
            end else begin
                case (clint_raddr_i[11:0])
                    `CSR_CYCLE: begin
                        clint_data_o = cycle[31:0];
                    end
                    `CSR_CYCLEH: begin
                        clint_data_o = cycle[63:32];
                    end
                    `CSR_MTVEC: begin
                        clint_data_o = mtvec;
                    end
                    `CSR_MCAUSE: begin
                        clint_data_o = mcause;
                    end
                    `CSR_MEPC: begin
                        clint_data_o = mepc;
                    end
                    `CSR_MIE: begin
                        clint_data_o = mie;
                    end
                    `CSR_MSTATUS: begin
                        clint_data_o = mstatus;
                    end
                    `CSR_MSCRATCH: begin
                        clint_data_o = mscratch;
                    end
                    default: begin
                        clint_data_o = `ZeroWord;
                    end
                endcase
            end
        end
    end


endmodule